#!/bin/bash
#
# hzclish - Hubzilla (ex Red Matrix) cli bash script.
# Version 2.2.1
# Source: https://notabug.org/uzver/hzclish
#
# License: WTFPL2 http://wtfpl2.com/
# uzver(at)protonmail.ch
#
# Dependenciess:
#  curl, jq, awk, grep, sed
#    perl libtext-markdown-perl libtext-typography-perl md2bbc.pl
#      or
#    pandoc lua bbcode_phpbb.lua


thispath="$(realpath $0)"
thisdir="$(dirname "$thispath")"
dotdir=~/'.hzclish'
verbose=0
ssl=1
useragent='Mozilla/5.0 (Windows NT 6.1; rv:41.0) Gecko/20100101 Firefox/41.0'
mimetype='text/bbcode'
postpublic=1

# Functions to write output nicely
print_msg() {
    if [[ -t 0 ]]; then
    	echo -e "\e[0;36m$*\e[m"
    else
    	echo -e "$*"
    fi
}
print_msgn() {
    if [[ -t 0 ]]; then
    	echo -en "\e[0;36m$*\e[m"
    else
    	echo -en "$*"
    fi
}
print_notice() {
    if [[ -t 0 ]]; then
    	echo -en '\e[37;34m'"\e[1m[notice] \e[m"; echo "$*"
    else
    	echo -e "[notice] $*"
    fi
}
print_success() {
    if [[ -t 0 ]]; then
    	echo -en '\e[37;34m'"\e[1m[success] \e[m"; echo "$*"
    else
    	echo -e "[success] $*"
    fi
}
print_warn() {
    if [[ -t 0 ]]; then
    	echo -en "\e[0;33m[warning] \e[m" 1>&2; echo "$*" 1>&2
    else
    	echo -e "[warning] $*" 1>&2
    fi
}
print_error() {
    if [[ -t 0 ]]; then
    	echo -en '\e[37;31m'"\e[1m[error] \e[m" 1>&2; echo "$*" 1>&2
    else
    	echo -e "[error] $*" 1>&2
    fi
}
print_red() {
    if [[ -t 0 ]]; then
    	echo -en "\e[0;31m$*\e[m"
    else
    	echo -e "$*"
    fi
}
print_redbold() {
    if [[ -t 0 ]]; then
    	echo -e "\e[37;31m\e[1m$*\e[m"
    else
    	echo -e "$*"
    fi
}

# MAIN FUNCTIONS:
USAGE(){
    exec=$(basename "$0"); [[ "$exec" ]] || exec="${0##*/}"
    cat << EOF
  $exec - CLI bash wrapper script for the Hubzilla (Red Matrix) zot API.

  USAGE: $exec [OPTIONS] [-u LOGIN:DOMAIN[:PASSWORD]] [<<<"MESSAGE"]

  OPTIONS:
    -B                          BBCODE mimetype post. Send post as bbcode.
                                 (By default this script converts your post via markdown to bbcode.
                                  You can Use this option if you prefer to write the post in bbcode
                                  or plain text so post message won't be converted to bbcode).
    -c config                   Specify config file to use.
                                 (use different configs for different accounts).
    -d                          Set config file as default auth (requires: -s|-g|-p).
    -D                          Delete config and cookie files.
    -g id|mid                   Get item (post) of given id or mid.
    -h, --help                  Show this help.
    -H                          HTML mimetype post. Send post as html.
                                 (By default this script converts your post via markdown to bbcode.
                                  Use this option if you prefer to write the post in html.
                                  Server will store the post as html. Hashtags won't works in this case.
                                  Post message won't be converted to html or bbcode).
    -i                          Post from standart input.
    -m <str>                    Set your custom markdown converter engine (overwrites: -P).
                                  You can use this option e.g. to set the engine as 'markdown'
                                  and also pass the -H option, and write post in markdown.
                                  In this way the post will be converted to html so the server will get
                                  and store the post as html. Hashtags won't works in this case.
    -M                          MARKDOWN mimetype post. Send post as markdown.
                                 (By default this script converts your post via markdown to bbcode.
                                  Use this option to let the server to store the post
                                  as markdown. Hashtags won't works in this case.
                                  Post message won't be converted to bbcode or html).
    -p                          Post the message.
    -P                          Use pandoc instead of md2bbc.pl to convert markdown to bbcode
                                 (it's short for:
                                  -m "pandoc -f markdown_strict+footnotes+definition_lists+hard_line_breaks -t ${thisdir}/bbcode_phpbb.lua").
    -q                          Less verbose printing.
    -R                          Renew auth token.
    -s                          Set new authentification (save login, password).
    -S yes|no                   Use or not https (default: yes) (useful for inline auth: -u).
    -t                          Convert very last line (of your post) with hashtags to categories,
                                 and post with the same hashtags and categories.
    -T                          Convert very last line (of your post) with hashtags to categories,
                                 and drop hashtags. Post only with categories.
    -u LOGIN:DOMAIN[:PASSWORD]  Specify auth inline, e.g.:
                                 "inbox@example.com:hubdomain.com:password",
                                 or:
                                  "channelname@hubdomain.com:password", or:
                                  "channelname@hubdomain.com"
                                 (use it if you do not want to save auth)
                                 (implies not to use with: -c, -D, -r, -s).
    -v                          Verbose mode.

  EXAMPLES:
    Save new authentification to config file and set it default:
      $exec -s
     or save new auth and set it default:
      $exec -vds                               # verbose
     or to custom place or name:
      $exec -vc ~/myConfig -s                  # save to myConfig file in home
                                                  directory
      $exec -vc myConfig -s                    # save to "$dotdir"/myConfig file
     or to custom place or name and set default:
      $exec -vdc ~/myConfig -s                 # save to myConfig file in home
                                                  directory
      $exec -vdc myConfig -s                   # save to "$dotdir"/myConfig file

    Post message:
      $exec
      $exec -vp
      $exec -c myConfig                        # with custom config
      $exec -dc myNewDefaultConfig             # with custom config & set it
                                                  default

    Post message from stdin:
      $exec <<<"Hello world!"
      echo "Hello world!" | $exec
      cat myPost.md | $exec

    Get item by id or mid:
      $exec -g 1234567
      $exec -g 80833f7ead182a3f5b39079c3b3974acf4828e1113193a3160bd6c29df1f8c89@lastauth.com
      $exec -c myConfig -g 1234567             # with custom config
      $exec -dc myNewDefaultConfig -g 1234567  # with custom config & set it
                                                  default
EOF
}

CONFIG(){
    # Check for config file and create new one if it does not exist
    if ! (($custconfig)) && ! (($setnew)); then
        confdir="$dotdir"
        if  [[ -f "${confdir}/defaultconfig" ]]; then
            source "${confdir}/defaultconfig"
        else
            print_error "Can't find defaultconfig"
            exitstatus=1
        fi
    else
        ! (($quiet)) && (($verbose)) && [[ $config ]] && print_msg "Using config: $config"
        # Find directory of config file if '$config' is file and set it as config directory '$confdir'
        [[ -f "$config" ]] && confdir=$(dirname "$config")
        # In case '$config' is zid:
        #  set config directory to script dot directory '$dotdir'
        [[ -d "$confdir" ]] || confdir="$dotdir"
        # Create path to config file and set it as '$config'
        if [[ -f "$config" ]]; then
            true
        else
            if [[ -f "${confdir}/$config" ]]; then
                config="${confdir}/$config"
            elif [[ -f "${confdir}/${config}.config" ]]; then
                config="${confdir}/${config}.config"
            fi
        fi
# echo confdir "$confdir"
# echo config "$config"
# exit
    fi

    if [[ -f "$config" ]]; then
        ! (($quiet)) && (($verbose)) && print_msg "Using config: $config"
        # (($custconfig)) && confdir=$(dirname "$config")
        if (($setdefconf)); then
            ! (($quiet)) && (($verbose)) && print_msg "Setting default config to: $config"
            echo "config=\"$config\"">"${confdir}/defaultconfig" && [[ -f "${confdir}/defaultconfig" ]] && chmod 600 "${confdir}/defaultconfig"
        fi
    else
        mkdir -p "$confdir" && chmod 700 "$confdir"
        print_notice "Creating new config file:"
        read -p "Enter hub domain (example.com): " domain
        domain=$(echo "${domain%/*}" | sed 's|^[[:space:]]*https\?://||g')
        if ! (($sslsetted)); then
            validsslres=0
            sslres=y
            while ! (($validsslres)); do
                read -n 1 -p "Does your hub use SSL? (Y/n): " sslres
                if [[ "${sslres,,}" == [Nn] ]]; then
                    validsslres=1
                    ssl=0
                    hub="http://$domain"
                elif [[ "${sslres,,}" == [Yy] || -z "$sslres" ]]; then
                    validsslres=1
                    ssl=1
                    hub="https://$domain"
                else
                    validsslres=0
                    print_error "\nResponse not valid, please answer \"y\" or \"n\""
                fi
            done
            echo
        fi
        if (($ssl)); then
            hub="https://$domain"
        else
            hub="http://$domain"
        fi
        read -p "Enter login e-mail: " login
        read -p "Enter nickname (channel nickname) (or leave blank): " channel
        if [[ "$channel" ]]; then
            zid="${channel}@$domain"
        elif [[ "$login" ]]; then
            zid="${login}@$domain"
        fi
        if ! [[ "$login" ]]; then
            echo 'Please specify login'
            exitstatus=1
            (($verbose)) && print_msg "Exiting"
            exit $exitstatus
        fi
        if ! (($custconfig)); then
            config="${confdir}/${zid}.config"
        fi
        # if [[ "$(grep 'token=.\+' "$config")" ]]; then
        [[ -f "$config" ]] && source "$config"
        if [[ "$token" ]]; then
            print_error "Script appears to be registered previously"
            echo "        Use: "$exec" '-D ${zid}' to delete auth and then '-s' option to try again" 1>&2
            (($verbose)) && print_msg "Exiting"
            exit 1
        fi
        if (($setdefconf)) || [[ ! -f "${confdir}/defaultconfig" || "$(wc -m "${confdir}/defaultconfig"|cut -d ' ' -f 1)" == 0 ]]; then
            ! (($quiet)) && (($verbose)) && print_msg "Setting default config to: $config"
            echo "config=\"$config\"">"${confdir}/defaultconfig" && [[ -f "${confdir}/defaultconfig" ]] && chmod 600 "${confdir}/defaultconfig"
        fi
        cookie="${zid}.cookie"
{
cat << EOF
hub="$hub"
login="$login"
channel="$channel"
zid="$zid"
useragent="$useragent"
cookie="\${zid}.cookie"
EOF
}>"$config"
        [[ -f "$config" ]] && chmod 600 "$config"
        if ! (($quiet)) && (($verbose)); then
            print_msg "These variables have been saved to ${config}:"
            #echo -e "\e[0;36m"; cat "$config"; echo -e "\e[m"
            tput setaf 6;echo; cat "$config"; echo;tput sgr0
        fi
    fi
    source "$config"
    [[ -f "${confdir}/${zid}.cookie" ]] || (touch "${confdir}/${zid}.cookie" && chmod 600 "${confdir}/${zid}.cookie")

    if ! (($pandoc)) && ! [[ "$mdexec" ]]; then
        if [[ "$(which md2bbc >& /dev/null; echo $?)" == 0 || -f ~/"bin/md2bbc" ]]; then
            markdown="md2bbc"
        elif [[ -f ~/"bin/md2bbc.pl" ]]; then
            markdown=~/"bin/md2bbc.pl"
        elif [[ -f "${thisdir}/md2bbc.pl" ]]; then
            markdown="${thisdir}/md2bbc.pl"
        elif [[ -f "${confdir}/md2bbc.pl" ]]; then
            markdown="${confdir}/md2bbc.pl"
        elif [[ -f "${dotdir}/md2bbc.pl" ]]; then
            markdown="${dotdir}/md2bbc.pl"
        else
            print_error "No md2bbc.pl script was found. Please install the md2bbc.pl script to one of these locations: ~/bin, ~/.hzclish or near to hzclish script or use the pandoc via -P option"
            (($verbose)) && print_msg "You can find the script in git repo"
            exitstatus=1
        fi
    fi
    if [[ "$(which jq >& /dev/null; echo $?)" == 0 ]]; then
        jq="jq"
    elif [[ -f ~/"bin/jq" ]]; then
        jq=~/"bin/jq"
    elif [[  -f "${thisdir}/jq" ]]; then
        jq="jq"
    elif [[ -f "${confdir}/jq" ]]; then
        jq="jq"
    elif [[ -f "${dotdir}/jq" ]]; then
        jq="jq"
    fi
}

PASSWORD(){
unset password
if [[ "$config" ]] && [[ "$(grep 'password=' "$config")" ]]; then
    source "$config"
else
    echo ""
    // Read password user input
    prompt="What is your password?: "
    while IFS= read -p "$prompt" -r -s -n 1 char
    do
        if [[ $char == $'\0' ]]; then
            break
        fi
            prompt='*'
            password+="$char"
    done
    echo -e "\n"
fi
}

SETAUTH(){
    CONFIG
    source "$config"
    if ! [[ "$password" ]]; then
        print_notice "This is the only time you asked for your password"
        echo "Your password will be stored plain in config file"
        PASSWORD
    fi
    sed -i '/password=/d' "$config"
    echo password=\"$(sed 's/\"/\\"/g'<<<"$password")\">>"$config"
    if (($verbose)); then
        print_msg "Password have been saved to $config"
    fi

    # source "$config"
    echo "Getting token..."
    getauth=$(curl -ksSi --trace-ascii - \
        -u "${login}:${password}" \
        --cookie-jar "${confdir}/$cookie" --cookie "${confdir}/$cookie" \
        -H "User-Agent: $useragent" \
        "${hub}/api/z/1.0/abconfig")
    token=$(echo "$getauth"|sed -n 's/^.*[aA]uthorization: [Bb]asic \(.*\)/\1/p1')

    # unset getauth
    if [[ "$token" ]]; then
        sed -i '/token=/d' "$config"
        echo "token=\"${token}\"">>"$config"
        # unset token
        if (($verbose)); then
            print_success "Token saved"
        fi
    else
        print_error "Getting token failed. Check/set your login/password/connection"
(($verbose)) && print_redbold "[post]" 1>&2 && echo "$getauth" 1>&2
        unset getauth
        (($verbose)) && print_msg "Exiting"
        exitstatus=1
    fi

    local error=''
    error=$(echo "$getauth" | grep -io '^This api requires login')
    [[ "$error" ]] || error=$(echo "$getauth" | grep -o '^HTTP/[[:digit:]]\.[[:digit:]] \+[3-9]\{1,3\}.*')
    if [[ "$error" ]]; then
        [[ "$token" ]] && echo 'but' 1>&2
        unset token
        print_error "$error"
        echo "Check/set your login/password/server and try again" 1>&2
        (($verbose)) && print_msg "Exiting"
        exitstatus=1
    fi

    if (($exitstatus)); then
        (($verbose)) && print_msg "Exiting"
        exit $exitstatus
    fi
}

RETOKEN(){
    CONFIG
    source "$config"
    while [[ ! $retokened ]]; do
        if ! (($quiet)) && (($verbose)); then
            print_msg "Getting new token..."
        fi
        if ! [[ "$password" ]]; then
            PASSWORD
        fi
        getauth=$(curl -ksSi --trace-ascii - \
            -u "${login}:$password" \
            --cookie-jar "${confdir}/$cookie" --cookie "${confdir}/$cookie" \
            -H "User-Agent: $useragent" \
            "${hub}/api/z/1.0/abconfig")
        local body=$(echo -n "$getauth"|grep -iom1 '{\".*[^\]\(["}]\|\]\)}')
        [[ "$body" ]] || body=$(echo -n "$getauth"|grep -i 'error')
        unset password
        token=$(echo "$getauth"|sed -n 's/^.*[aA]uthorization: [Bb]asic \(.*\)/\1/p1')

        # unset getauth
        if [[ "$token" ]]; then
            sed -i '/token/d' "$config"
            echo "token=\"${token}\"">>"$config"
            # unset token
            if (($verbose)); then
                print_success "Token saved"
            fi
        else
            print_error "Getting new token failed. Check/set your login/password/server"
(($verbose)) && print_redbold "[post]" 1>&2 && echo "$getauth" 1>&2
unset getauth
            # (($verbose)) && print_msg "Exiting"
            exitstatus=1
        fi

        local error=''
        error=$(echo "$getauth" | grep -io '^This api requires login')
        [[ "$error" ]] || error=$(echo "$getauth" | grep -o '^HTTP/[[:digit:]]\.[[:digit:]] \+[3-9]\{1,3\}.*')
        if [[ "$error" ]]; then
            [[ "$token" ]] && echo 'but'
            unset token
            print_error "$error"
            (($verbose)) && [[ "$body" ]] && print_red "$body" 1>&2
            echo "Check/set your login/password/server" 1>&2
            # (($verbose)) && print_msg "Exiting"
            exitstatus=1
        fi

        if (($exitstatus)); then
            (($verbose)) && print_msg "Exiting"
            exit $exitstatus
        fi
        ((retokened++))
    done
}

GETPOST(){
    if ! (($inlineauth)); then
        CONFIG
        source "$config"
        unset password
    fi
    local mid='' pid='' posturl='' posturl2='' username='' useraddr='' userurl='' userhub='' posttitle=''
    local post=$(mktemp /tmp/hzpost.XXXXXX)
    local postbody=$(mktemp /tmp/hzpostbody.XXXXXX)
    if [[ "$1" ]]; then
        if [[ "$1" =~ .+@.+ ]]; then
            mid="$1"
            local req="mid=${mid%%&*}"
        elif [[ "$mid" =~ ^b64\.+ ]]; then
            mid="$1"
            mid=$(base64 -d <<<"${mid#b64.}" 2>&1); mid="${mid%base64*}"; mid="${mid##*/}"
            local req="mid=${mid%%&*}"
        else
            pid="$1"
            local req="item_id=${pid}"
        fi
    else
        echo 'Please specify the message id'
        (($verbose)) && print_msg "Exiting"
        exit 1
    fi
    [[ "$2" == 'urlonly' ]] && local urlonly=1
    GETPOSTINIT(){
        if (($inlineauth)); then
            ! [[ "$password" ]] && PASSWORD
            (($verbose)) && print_msg "Getting post ${req#*=} ..."
            curl -ksSi -u "${login}:$password" \
                -H "User-Agent: $useragent" \
                -H "Content-Type: application/json" \
                -H 'Accept: application/json' \
                "${hub}/api/z/1.0/item/full?$req" >"$post"
            unset password
        else
            (($verbose)) && print_msg "Getting post ${req#*=}..."
            (($verbose)) && echo -e "curl -ksSi -H \"Authorization: Basic $token\" --cookie-jar \"${confdir}/$cookie\" --cookie \"${confdir}/$cookie\" -H \"User-Agent: $useragent\" -H \"Content-Type: application/json\" -H \"Accept: application/json\" \"${hub}/api/z/1.0/item/full?$req\""
            curl -ksSi \
                -H "Authorization: Basic $token" \
                --cookie-jar "${confdir}/$cookie" --cookie "${confdir}/$cookie" \
                -H "User-Agent: $useragent" \
                -H "Content-Type: application/json" \
                -H "Accept: application/json" \
                "${hub}/api/z/1.0/item/full?$req" >"$post"
            unset password
            unset token
        fi
        grep -iom1 '{\".*[^\]\(["}]\|\]\)}' "$post" >"$postbody"
        local postbodylength=$(wc -m "$postbody"|cut -d ' ' -f 1)
        if (($postbodylength)); then
            pid=$("$jq" -r '.item|.[].id' "$postbody")
            mid=$("$jq" -r '.item|.[].message_id' "$postbody")
            posturl=$("$jq" -r '.item|.[].permalink' "$postbody")
#            posturl2="$(echo -n "$posturl"|sed 's|^.*\(https\?://[^/]\+\)/.*|\1|')/display/${mid##*/}"
#            posturl2="$(echo -n "$posturl"|sed 's|^.*\(https\?://[^/]\+\)/.*|\1|')/item/${mid##*/}"
            if ! (($urlonly)); then
                username=$("$jq" -r '.item|.[].author.name' "$postbody")
                useraddr=$("$jq" -r '.item|.[].author.address' "$postbody")
                userurl=$("$jq" -r '.item|.[].author.url' "$postbody")
                userhub=$(echo -n "$userurl"|sed 's|^.*https\?://\([^/]\+\)/.*|\1|')
                posttitle=$("$jq" -r '.item|.[].title' "$postbody")
            fi
        fi
    }
    GETPOSTINIT
    local error=''
    error=$(grep -io '^This api requires login' "$post")
    [[ "$error" ]] || error=$(grep -o '^HTTP/[[:digit:]]\.[[:digit:]] \+[3-9]\{1,3\}.*' "$post")
    if [[ "$error" ]]; then
        if [[ $retokened != 1 ]] && [[ $inlineauth != 1 ]]; then
            if ! (($quiet)); then
                # print_error "$error"
                print_warn "$error"
                echo "Error or invalid token, requesting new one..." 1>&2
            fi
            RETOKEN
            GETPOSTINIT
            local error=''
            error=$(grep -io '^This api requires login' "$post")
            [[ "$error" ]] || error=$(grep -o '^HTTP/[[:digit:]]\.[[:digit:]] \+[3-9]\{1,3\}.*' "$post")
            if [[ "$error" ]]; then
                print_error "$error"
                echo "Can't get post due authorization issue" 1>&2
                echo "Check/set your login/password/server and try to get post again" 1>&2
                (($verbose)) && print_msg "Exiting"
                exit 1
            fi
        else
            print_error "$error"
            echo "Can't get post due authorization issue" 1>&2
            echo "Check/set your login/password/server and try to get post again" 1>&2
            (($verbose)) && print_msg "Exiting"
            exit 1
        fi
    fi

    if [[ "$mid" || "$pid" ]]; then
        if ! (($urlonly)); then
            print_msg "$useraddr:\n"
            [[ "$posttitle" ]] && echo -e "${posttitle}\n"
            "$jq" -r '.item|.[].body' "$postbody"
            if ! (($quiet)); then
#                echo -e "\n\e[0;36m""post url: $posturl2""\e[m"
                print_msg "\npost url: $posturl"
                (($verbose)) && print_msg "post id: $pid"
                (($verbose)) && print_msg "user url: $userurl"
            fi
        else
#            echo -e "\n\e[0;36m""$posturl2""\e[m"
            print_msg "\n$posturl"
        fi
    else
        print_error "No post returned, please try again or give up"
(($verbose)) && print_redbold "[post]" 1>&2 && cat "$post" 1>&2
        (($verbose)) && print_msg "Exiting"
        exit 1
    fi
    /bin/rm -f "$post" "$postbody"
}

POST(){
    if ! (($inlineauth)); then
        CONFIG
        source "$config"
        unset password
    fi
    if ! (($hasmsg)); then
        local message=$(mktemp /tmp/hzmessage.XXXXXX)
        local msgbody=$(mktemp /tmp/hzmsgbody.XXXXXX)
    else
        local message="$message"
        local msgbody="$msgbody"
# echo HAS MESSAGE
# echo
# echo verbose "$verbose"
# echo hasmsg "$hasmsg"
# echo msgbody "$msgbody"
# echo message "$message"
# echo tagline "$tagline"
# echo tags "$tags"
# echo catline "$catline"
# cat "$message"
# exit
    fi
    [[ -f "$message" && -f "$msgbody" ]] && chmod 600 "$message" "$msgbody"
    local mid='' pid='' success='' error='' posturl='' posturl2=''
    local post=$(mktemp /tmp/hzpost.XXXXXX)
    local postbody=$(mktemp /tmp/hzpostbody.XXXXXX)

        if ! (($hasmsg)); then
            if ! [[ -t 0 ]] || (($stdin)); then
                eval 'stdin=$(cat); echo "$stdin"' >"$message"
            else
                $EDITOR "$message"
            fi
            msglength=$(wc -m "$message"|cut -d ' ' -f 1)
            if ! (($msglength)); then
                print_error "The message is empty. Not posting message"
                echo "Not deleting the file \"$message\" in case it is not empty" 1>&2
                /bin/rm -f "$msgbody"
                exitstatus=1
                (($verbose)) && print_msg "Exiting"
                exit $exitstatus
            fi
            ## Delete leading blank lines
            sed -i '/./,$!d' "$message"

            msglines=$(wc -l "$message"|cut -d ' ' -f 1)
        fi
        # Make tags only if message length more than 1 line
        if [[ ! "$tagline" ]] && [[ "$msglines" -gt 1 ]]; then
            tagline=$(tail -n 1 "$message" | grep -io '^[[:space:]]*\?\#.*\?')
            [[ "$tagline" ]] && hastagline="$tagline"
            ! (($catonly)) && tags=$(echo "$tagline" | sed 's|^[[:space:]]*||; s|,||g')
        fi
#cat "$message"; exit
        if [[ ! "$catline" ]]; then
            catline=$(head -n 1 "$message" | grep -iom1 '^[[:space:]]*\?\*.*\?')
            [[ "$catline" ]] && hascatline=1
            (($tagtocat)) && catline=$(echo "$tagline" | sed 's|^[[:space:]]*\?\#|\*|g; s|[[:space:]]*\?\#| \*|g')
        fi
        catsarr=($(echo "$catline" | sed 's|[\*]| |g; s|^[[:space:]]*||; s|,||g; s/\"/\\"/g'))
        local category=''
        for c in "${catsarr[@]}"; do category+="${c},"; done
        # (($catonly)) && tagline='' && tags=''
# echo verbose "$verbose"
# echo hasmsg "$hasmsg"
# echo msgbody "$msgbody"
# echo message "$message"
# echo tagline "$tagline"
# echo hastagline "$hastagline"
# echo tags "$tags"
# echo catline "$catline"
# echo catsarr "${catsarr[@]}"
# echo category "$category"
# cat "$message"
# echo
        # msg=$(cat "$message")
        cp "$message" "$msgbody"
# echo msg "$msg"
# echo
# echo
# exit
        if ! (($catonly)); then
            if [[ "$tagline" || "$hastagline" ]]; then
                echo "$(awk -F "$tagline" '{print $1}' "$msgbody")" >"$msgbody"
            fi
        else
            tagline='' && tags=''
            [[ "$hastagline" ]] && echo "$(awk -F "$hastagline" '{print $1}' "$msgbody")" >"$msgbody"
        fi
#cat "$msgbody"; exit
# echo msg "$msg"
# echo hasmsg $hasmsg
# echo hastagline $hastagline
# echo hascatline $hascatline
# echo catline "$catline"
# exit
        if ! (($hasmsg)) && ! (($tagtocat)) && (($hascatline)); then
            # FIXME: slow part
            [[ "$catline" ]] && echo "$(awk -v cl="$catline" '$0 == cl {i=1;next};i && i++ <= 999' "$msgbody")" >"$msgbody"
            ## Delete leading blank lines
            sed -i '/./,$!d' "$msgbody"
        fi
#cat "$msgbody"; exit
# exit
        # titleline=$(head -n 1 "$msgbody" | grep -iom1 '^[[:space:]]*\?\#[[:space:]]\+.*\?')
        # [[ "$titleline" ]] && sed -i '/'"$titleline"'/d' "$msgbody"
        # [[ "$titleline" ]] && echo "$(awk -F "$titleline" '{print $1}' "$msgbody")" >"$msgbody"
        title=$(head -n 1 "$msgbody" | grep -iom1 '^[[:space:]]*\?\#[[:space:]]\+.*\?' | sed 's/^[[:space:]]*\?\#[[:space:]]\+//g')
#cat "$msgbody"; exit
        ## If title field seted than delete title from body
        [[ "$title" ]] && sed -i 1d "$msgbody"
#cat "$msgbody"; exit
        ## Delete leading blank lines
        sed -i '/./,$!d' "$msgbody"
#cat "$msgbody"; exit
# exit
# echo hasmsg $hasmsg
# echo hastagline $hastagline
# echo hascatline $hascatline
# echo message "$message"
# echo tagline "$tagline"
# echo tags "$tags"
# echo catline "$catline"
# echo catsarr "${catsarr[@]}"
# echo title "$title"
# echo -n 'message '; cat "$message"; echo
# echo msg "$msg"
# exit
        # [[ "$title" ]] && echo "title=\"$title\"">"$msgbody"
        # [[ "$category" ]] && echo "category=\"${category%,}\"">>"$msgbody"
        if (($pandoc)); then
            if [[ -f ~/"bin/bbcode_phpbb.lua" ]]; then
                bbcode=~/"bin/bbcode_phpbb.lua"
            elif [[ -f "${thisdir}/bbcode_phpbb.lua" ]]; then
                bbcode="${thisdir}/bbcode_phpbb.lua"
            elif [[ -f "${confdir}/bbcode_phpbb.lua" ]]; then
                bbcode="${confdir}/bbcode_phpbb.lua"
            elif [[ -f "${dotdir}/bbcode_phpbb.lua" ]]; then
                bbcode="${dotdir}/bbcode_phpbb.lua"
            else
                print_error "No bbcode_phpbb.lua was found. Please install the bbcode_phpbb.lua script to one of these locations: ~/bin, ~/.hzclish or near to hzclish script"
                (($verbose)) && print_msg "You can find the script in git repo"
                exitstatus=1
            fi
            # markdown="pandoc -f markdown -t $bbcode" # (pandoc's extended markdown)
            # markdown="pandoc -f markdown_phpextra -t $bbcode" # (PHP Markdown Extra extended markdown)
            # markdown="pandoc -f markdown_github -t $bbcode" #  (github  extended  markdown)
            # markdown="pandoc -f markdown_strict+footnotes+definition_lists+hard_line_breaks -t $bbcode" # (original unextended markdown + with footnotes and definition lists and hard line breaks)
            markdown="pandoc -f markdown_strict+footnotes+definition_lists+hard_line_breaks -t $bbcode" # (original unextended markdown + with footnotes and definition lists and hard line breaks)
        elif [[ "$mdexec" ]]; then
            markdown="$mdexec"
        fi

        if (($exitstatus)); then
            (($verbose)) && print_msg "Exiting"
            exit $exitstatus
        fi

        #echo "$(if (($mimebb)) || (($mimehtml)); then cat "$msgbody"; else cat "$msgbody"|$markdown; fi; [[ "$tags" ]] && echo -en "\n$tags")" >"$msgbody"
        # If custom markdown not set and custom mimetype is set, then do not convert
        if ! [[ "$mdexec" ]] && ((($mimebb)) || (($mimehtml)) || (($mimemarkdown))); then
            # do not convert (let server handle it according mimetype)
            true
        else
            if (($pandoc)); then
                # use pandoc to markdown to bbcode
                $markdown -o "$msgbody" <"$msgbody"
            else
                # use chosen markdown engine to markdown
                $markdown <"$msgbody" 1<>"$msgbody"
            fi
        fi
#cat "$msgbody"
#exit
        [[ "$tags" ]] && echo -en "\n$tags" >>"$msgbody"
        # [[ "$htmlstatus" ]] && echo "htmlstatus=\"$htmlstatus\"">>"$msgbody"
# echo msg "$msg"
#echo $title;  exit
        # source "$msgbody"
# echo " export token='$token'"
# echo " export useragent='$useragent'"
# echo " export hub='$hub'"
# echo " export title='$title'"
# echo " export category='$category'"
# echo " export channel='$channel'"
# echo " export htmlstatus='$htmlstatus'"
# echo " export cookie='$cookie'"
# exit
    POSTINIT(){
        if (($inlineauth)); then
            ! [[ "$password" ]] && PASSWORD
            (($verbose)) && print_msg "Posting..."
            cat "$msgbody" | curl -ksSi \
            -u "${login}:$password" \s
            -H "User-Agent: $useragent" \
            -X POST \
            "${hub}/api/z/1.0/item/update" \
            -F "title=$title" \
            -F "category=$category" \
            -F "mimetype=$mimetype" \
            $((($postpublic)) && echo "-F group_allow=") \
            -F 'body=<-' >"$post"
            unset password
        else
            (($verbose)) && print_msg "Posting..."
            cat "$msgbody" | curl -ksSi \
            -H "Authorization: Basic $token" \
            --cookie-jar "${confdir}/$cookie" --cookie "${confdir}/$cookie" \
            -H "User-Agent: $useragent" \
            -X POST \
            "${hub}/api/z/1.0/item/update" \
            -F "title=$title" \
            -F "category=$category" \
            -F "mimetype=$mimetype" \
            $((($postpublic)) && echo "-F group_allow=") \
            -F 'body=<-' >"$post"
            unset password
            unset token
        fi
# cat "$post"
# exit
        grep -iom1 '{\".*[^\]\(["}]\|\]\)}' "$post" >"$postbody"
        local postbodylength=$(wc -m "$postbody"|cut -d ' ' -f 1)
        (($postbodylength)) && success=$("$jq" -r '.success' "$postbody")
        if [[ "$success" == "true" ]]; then
            pid=$("$jq" -r '.item_id' "$postbody")
            mid=$("$jq" -r '.item.mid' "$postbody")
            posturl=$("$jq" -r '.item.plink' "$postbody")
            posturl2=$("$jq" -r '.item.llink' "$postbody")
        fi
    }
    POSTINIT
    error=$(grep -io '^This api requires login' "$post")
    [[ "$error" ]] || error=$(grep -o '^HTTP/[[:digit:]]\.[[:digit:]] \+[3-9]\{1,3\}.*' "$post")
# echo error "$error"
# exit
    # if [[ "$error" ]]; then
    if [[ "$error" || "$success" == "false" ]]; then
        [[ "$error" ]] || error=$("$jq" -r '.message' "$postbody")
        if [[ "$error" == 'no content' ]]; then
            if ! (($quiet)); then
                print_error "$error"
                echo "Error or invalid token, requesting new one..." 1>&2
            fi
            (($verbose)) && print_msg "Exiting"
            exit 1
        else
            if ! (($retokened)) && ! (($inlineauth)); then
                if ! (($quiet)); then
                    # print_error "$error"
                    print_warn "$error"
                    echo "Error or invalid token, requesting new one..." 1>&2
                fi
                RETOKEN
                local success=''; local error=''
                POSTINIT
                error=$(grep -io '^This api requires login' "$post")
                [[ "$error" ]] || error=$(grep -o '^HTTP/[[:digit:]]\.[[:digit:]] \+[3-9]\{1,3\}.*' "$post")
                if [[  "$error" || "$success" == "false" ]]; then
                    [[ "$error" ]] || error=$("$jq" -r '.message' "$postbody")
                    print_error "$error"
                    echo "Can't post due authorization issue" 1>&2
                    echo "Check/set your login/password/server and try to post again" 1>&2
                    (($verbose)) && print_msg "Exiting"
                    exit 1
                fi
            else
                print_error "$error"
                echo "Can't post due authorization issue" 1>&2
                echo "Check/set your login/password/server and try to post again" 1>&2
                (($verbose)) && print_msg "Exiting"
                exit 1
            fi
        fi
    fi

    if [[ "$pid" ]]; then
        if ! (($quiet)); then
            if [[ "$pid" ]]; then
                local id="$pid"
            elif [[ "$mid" ]]; then
                local id="$mid"
            fi
            print_success "Message posted with id: ${id}"
            print_msgn "post url: "
        fi
        print_msg "$posturl"
        /bin/rm -f "$message" "$msgbody"
    else
        print_error "No post id returned, please try again or give up"
(($verbose)) && print_redbold "[post]:\n" 1>&2 && print_red "$(cat "$post")" 1>&2
        echo "Message should still be saved in the file $message" 1>&2
        /bin/rm -f "$msgbody"
        (($verbose)) && print_msg "Exiting"
        exit 1
    fi
    /bin/rm -f "$post" "$postbody"
}

# DELETE CONFIG & COOKIE
DELETE(){
    ! (($quiet)) && (($verbose)) && [[ $zid ]] && print_msg "Using config: $zid"
    # Find directory of config file if '$config' is file and set it as config directory '$confdir'
    [[ -f "$zid" ]] && local confdir=$(dirname "$zid")
    # In case '$config' is zid:
    #  set config directory to script dot directory '$dotdir'
    [[ -d "$confdir" ]] || local confdir="$dotdir"
    # Create path to config file and set it as '$config'
    if [[ -f "$zid" ]]; then
        true
    else
        if [[ -f "${confdir}/${zid}" ]]; then
            local config="${confdir}/$zid"
            local cookie="${confdir}/${zid%.config}.cookie"
        elif [[ -f "${confdir}/${zid}.config" ]]; then
            local config="${confdir}/${zid}.config"
            local cookie="${confdir}/${zid%.config}.cookie"
        fi
    fi
    ! (($quiet)) && echo Deleting cookie: "$cookie"
    [[ -f "$cookie" ]] && /bin/rm -f "$cookie"
    ! (($quiet)) && echo Deleting config: "$config"
    [[ -f "$config" ]] && /bin/rm -f "$config"
}

if [[ $# -lt 1 ]]; then
    exe=1
    POST
elif [[ "$1" == '--help' ]]; then
    USAGE
    exit 0
fi

# RUN OPTIONS
while getopts "B:c:dD:g:hHim:MpPqRsS:tTu:v\?" OPTION
do
  case $OPTION in
    B)
      mimebb=1
      mimetype='text/bbcode'
      ;;
    c)
      if [[ "$OPTARG" ]]; then
        config="$OPTARG"
        custconfig=1
      fi
      ;;
    d)
      #if [[ "$OPTARG" ]]; then
      #  config="$OPTARG"
      #  custconfig=1
      #fi
      setdefconf=1
      ;;
    D)
      exe=1
      zid="$OPTARG"
      DELETE
      ;;
    g)
      exe=1
      id="$OPTARG"
      GETPOST "$id"
      ;;
    h)
      exe=1
      USAGE
      ;;
    H)
      mimehtml=1
      mimetype='text/html'
      ;;
    i)
      stdin=1
      ;;
    m)
      mdexec="$OPTARG"
      #html=1
      ;;
    M)
      mimemarkdown=1
      mimetype='text/markdown'
      ;;
    p)
      exe=1
      POST
      ;;
    P)
      pandoc=1
      #html=1
      ;;
    q)
      quiet=1
      ;;
    r)
      exe=1
      RETOKEN
      ;;
    s)
      exe=1
      setnew=1
      SETAUTH
      ;;
    S)
      sslarg="$OPTARG"
      if [[ "$sslarg" ]]; then
        if [[ "$sslarg" == [nN][oO] ]]; then
          ssl=0
          sslsetted=1
        elif [[ "$sslarg" == [yY][eE][sS] ]];   then
          ssl=1
          sslsetted=1
        fi
      else
        ssl=1
        sslsetted=1
      fi
      ;;
    t)
      tagtocat=1
      ;;
    T)
      tagtocat=1
      catonly=1
      ;;
    u)
      if [[ "$OPTARG" ]]; then
        # "user@example.com:hubdomain.com:password"
        haspass=$(echo "$OPTARG" | awk -F':' '{print $3}')
        login="${OPTARG%%:*}"
        if [[ "$haspass" ]]; then
          domainandpass="${OPTARG#*:}"
          domain="${domainandpass%%:*}"
          password="${domainandpass#*:}"
          unset haspass
          unset domainandpass
        else
          domain="${OPTARG##*:}"
        fi
        if (($ssl)); then
          hub="https://$domain"
        else
          hub="http://$domain"
        fi
        zid=""
        inlineauth=1
      fi
      ;;
    v)
      verbose=1
      ;;
    \?)
      # print_notice "Invalid option: -$OPTARG" 1>&2
      print_error "Invalid option"
      (($verbose)) && print_msg "Exiting"
      exit 1
      ;;
    :)
      print_error "Option -${OPTARG} requires an argument"
      (($verbose)) && print_msg "Exiting"
      exit 1
      ;;

    *)  echo "Unknown option '$OPTION'"; USAGE ;;
  esac
done
shift $(($OPTIND -1))
# echo $exe; exit
## Post if no other functional commands was given
if ! (($exe)); then
  exe=1
  POST
fi

exit 0

### TODO:
# read post + comments
# private post
# use keyring
# delete post
# comment post
# delete comment
# reshare post
# like, dislike
# attach image to post
# notifications
# debug
# version option
# webdav files
# more errors handle
